package cn.spy.threaddownload.thread;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.*;

/**
 * 线程池配置类
 * @author sunpeiyu
 * @date 2023-04-10
 */
@Configuration
public class ThreadConfig {

    /**
     * 最大线程数量
     */
    private static final int maxPoolSize = Runtime.getRuntime().availableProcessors() * 2 + 1;
    /**
     * 核心线程数量
     */
    private static final int corePoolSize = maxPoolSize - 1;
    /**
     * 空闲线程存活时间
     */
    private static final int keepAliveSeconds = 60;
    /**
     * 线程阻塞队列容量
     */
    private static final int queueCapacity = 1000;
    /**
     * 是否允许核心线程超时
     */
    private static final boolean allowCoreThreadTimeOut = false;
    /**
     * 线程前缀
     */
    private static final String THREAD_PREFIX = "DOWNLOADER_";

    @Bean
    @Scope("singleton")
    public ThreadPoolExecutor getExecutor() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize,
                keepAliveSeconds, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity), new InnerThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                        if (!e.isShutdown()) {
                            r.run();
                        }
                    }
                });
        executor.allowCoreThreadTimeOut(allowCoreThreadTimeOut);
        return executor;
    }


    static class InnerThreadFactory implements ThreadFactory {
        @Override
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            LocalDateTime ldt = LocalDateTime.now();
            DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyyMMd HH:mm:ss");
            thread.setName(THREAD_PREFIX + ldt.format(pattern));
            return thread;
        }
    }
}
